package cn.tedu.charging.order.rabbitmq.delay;

import cn.tedu.charging.order.rabbitmq.ChannelManager;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class DelayDemo {
    //定义好的死信结构的名称常量
    private static final String DELAY_EX="delay_ex";
    private static final String DELAY_Q="delay_q";
    private static final String DLX_EX="dlx_ex";
    private static final String DLX_Q="dlx_q";
    private static final String DLX_RK="dlx_rk";
    @Test
    public void delayDeclare() throws Exception {
        //拿到channel
        Channel channel = ChannelManager.createChannel();
        //1.声明延迟交换机 fanout
        channel.exchangeDeclare(DELAY_EX, BuiltinExchangeType.FANOUT);
        //2.声明死信交换机 direct
        channel.exchangeDeclare(DLX_EX, BuiltinExchangeType.DIRECT);
        //3.声明延迟队列 在属性中定义死信交换机和死信路由
        Map<String,Object> args=new HashMap<>();
        //给队列绑定死信交换机
        args.put("x-dead-letter-exchange",DLX_EX);
        //给队列绑定死信路由key
        args.put("x-dead-letter-routing-key",DLX_RK);
        channel.queueDeclare(DELAY_Q,false,false,false,args);
        //4.声明死信队列
        channel.queueDeclare(DLX_Q,false,false,false,null);
        //5.延迟队列绑定延迟交换机 直接绑
        channel.queueBind(DELAY_Q,DELAY_EX,"");
        //6.死信队列绑定死信交换机
        channel.queueBind(DLX_Q,DLX_EX,DLX_RK);
    }

    //延迟消息发送 必定携带一个属性expiration 延迟时间毫秒数
    @Test
    public void sendDelayMessage() throws IOException {
        //拿到channel
        Channel channel = ChannelManager.createChannel();
        //组织的是延迟消息
        byte[] body="delay message".getBytes(StandardCharsets.UTF_8);
        //处理消息延迟,使用的是消息的超时ttl属性
        AMQP.BasicProperties.Builder builder=new AMQP.BasicProperties.Builder();
        //延迟30秒钟
        builder.expiration("30000");
        //生产者 作为延迟的发送,将消息发送到延迟交换机
        channel.basicPublish("delay_ex","",builder.build(),body);
        log.info("发送延迟消息成功");
    }
    //消费方法 监听的不是延迟队列,而是死信队列
    @Test
    public void consumeDelayMessage() throws IOException, InterruptedException {
        Channel channel = ChannelManager.createChannel();
        //面向对象编程思想,使用的匿名内部类,实实在在把参数对象构造出来
        //lamda表达式,函数式编程,简洁的代码
        channel.basicConsume(DLX_Q,true,
                (consumerTag,message)->{
                    log.info("延迟消费者获取消息");
                },
                consumerTag->{});
        Thread.sleep(1000000);
    }
}
